package com.zsr.xmall.search.thread;

import java.util.concurrent.*;

/**
 * @author zhousiren
 * @description
 * @date 2022/7/10 1:03
 */
public class CompletableFutureTest {
    private static ExecutorService executor = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //test1();//测试 runAsync
        //test2();//测试 supplyAsync
        test5();
    }


    /**
     * 测试 runAsync
     * <p>
     * 【注意】runXxx 都是没有返回结果的，supplyXxxx都是可以获取返回结果的
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void test1() {
        System.out.println("main... start...");
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("结束运行：" + i);
        }, executor);

        System.out.println("main... end...");

    }

    /**
     * 测试捕捉异常
     * whenComplete 可以处理正常和异常的计算结果，exceptionally 处理异常情况
     * <p>
     * 【注意】方法不以 Async 结尾，意味着 Action 使用相同的线程执行，
     * 而 Async 可能会使用其他线程执行（如果是使用相同的线程池，也可能会被同一个线程选中执行）
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void test2() throws ExecutionException, InterruptedException {
        System.out.println("main... start...");
        //1.执行任务
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 0;
            System.out.println("结束运行：" + i);
            return i;
        }, executor).whenComplete((result, exception) -> {
            System.out.println("异步任务完成了，结果是：" + result + ";异常是:" + exception);
        }).exceptionally(throwable -> {
            return 10;
        });

        System.out.println("main... end..." + future.get());

    }

    /**
     * 测试handle
     * <p>
     * 和 complete 一样，可以对结果做最后的处理（可处理异常），可改变返回值
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void test3() throws ExecutionException, InterruptedException {
        System.out.println("main... start...");
        //1.执行任务
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 0;
            System.out.println("结束运行：" + i);
            return i;
        }, executor).handle((res, exception) -> {
            if (res != null) {
                return res * 2;
            }
            if (exception != null) {
                return 0;
            }
            return res;
        });
        System.out.println("main... end..." + future.get());
    }


    /**
     * 测试串行化 视频p199
     * 1）、thenRun: 不能获取到上一步的执行结果，无返回值
     * 2）、thenAcceptAsync: 能接收上一步结果，但是无返回值
     * 3）、thenApplyAsync: 能接收上一步结果，有返回值
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void test4() throws ExecutionException, InterruptedException {
        CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果：" + i);
            return i;
        }, executor).thenAcceptAsync(res -> {
            System.out.println("任务1已启动:" + res);
        }, executor).thenAcceptAsync(res -> {
            System.out.println("任务2已启动:" + res);
        }, executor);
    }

    /**
     * 两个future执行完成，才执行下一个future  视频200p
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void test5() throws ExecutionException, InterruptedException {
        System.out.println("main... start...");
        //1.执行任务
        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1结束运行");
            return i;
        }, executor);
        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程" + Thread.currentThread().getId());
            System.out.println("任务2结束运行");
            return "hello";
        }, executor);
        //【两个执行完成，才执行下一个任务】
        //【不能感知上个结果】任务1 和任务2 执行完成后才会执行 任务3
        /*future01.runAfterBothAsync(future02,()->{
            System.out.println("任务3开始");
        },executor);*/

        //runAfterBothAsync 和 runAfterBoth 的区别 Async会新开线程进行执行

        //【能感知上个结果】
        /*future01.thenAcceptBothAsync(future02,(f1,f2)->{
            System.out.println("任务3开始,之前的结果：" +f1 +","+f2);
        },executor);*/

        //【能感知结果,并返回结果】
        /*CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
            return "任务3开始,之前的结果：" + f1 + "," + f2;
        });
        System.out.println("main... end..." +future.get());*/

        //【只要一个执行完成，就执行下一个任务】
        //【不能感知上个结果】
        future01.runAfterEitherAsync(future02, () -> {
            System.out.println("执行任务3开始");
        }, executor);
    }

    /**
     * 两任务组合，一个完成，就执行任务3   视频201p
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void test6() throws ExecutionException, InterruptedException {
        //1.执行任务
        CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1结束运行");
            return i;
        }, executor);
        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程" + Thread.currentThread().getId());
            try {
                Thread.sleep(3000);//模拟任务2执行慢
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务2结束运行");
            return "hello";
        }, executor);

        //【不能感知上个结果】任务1和任务2有一个执行完成后就会执行任务3,无返回值
        future01.runAfterEitherAsync(future02, () -> {
            System.out.println("任务3开始");
        });
        //【能感知上个结果】 无返回值
        future01.acceptEitherAsync(future02, (res) -> {
            System.out.println("任务3开始...之前的结果是" + res);
        });
        //【能感知上个结果】 有返回值
        future01.applyToEitherAsync(future01, (res) -> {
            System.out.println("任务3开始...之前的结果是" + res);
            return res.toString() + "哈哈";
        });
    }

    /**
     * 任务组合  视频202
     * allOf：**等待所有任务完成**
     * anyOf:**只要有一个任务完成**
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void test7() throws ExecutionException, InterruptedException {
        System.out.println("main...start...");

        CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片信息");
            return "hello.jpg";
        });

        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的属性");
            return "黑色+256G";
        });

        CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("查询商品介绍");
            return "华为";
        });

        //错误实践
        /*futureImg.get();
        futureAttr.get();
        futureDesc.get();*/

        // 等待全部执行完
        //CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
        //allOf.get();

        //如果不调用allOf.get(),执行结果如下：
        /* main...start...
         * 查询商品的图片信息
         * 查询商品的属性
         * main...start...
         * 查询商品介绍  */

        //如果想获取单个结果
        //System.out.println(futureImg.get()+"=>"+futureAttr.get());


        // 只需要有一个执行完
        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
        anyOf.get();//成功的数据
        System.out.println(anyOf.get());


        System.out.println("main...start...");

    }


    /**
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void test11() throws ExecutionException, InterruptedException {
        // 5.1.提交任务异步执行(supplyAsync)
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "测试使用", executor);
        System.out.println(future1.get());
        // 5.2.获取上一步结果并链式异步调用(thenApplyAsync)【 能获取上一步结果 + 有返回值】
        CompletableFuture<String> future2 = future1.thenApplyAsync(s -> s + " 链式调用", executor);// 参数s是上一步的返回值
        System.out.println(future2.get());
        // 5.3.获取上一步执行结果并获取异常信息(whenCompleteAsync)
        CompletableFuture<String> future3 = future2.whenCompleteAsync((result, exception) -> System.out.println("结果是：" + result + "----异常是：" + exception));
        // 5.4.获取上一步异常，如果出现异常返回默认值，不出现异常保持原值(exceptionally)
        CompletableFuture<Integer> future4 = future3.thenApplyAsync((s -> 1 / 0), executor);
        CompletableFuture<Integer> future5 = future4.exceptionally(exception -> {
            System.out.println("出现异常：" + exception);
            return 10;
        });// 出现异常，使用默认返回值
        System.out.println("默认值：" + future5.get());
        // 5.5.方法执行完成后的处理
        CompletableFuture<Integer> future6 = future3.thenApplyAsync((s -> 1 / 0), executor).handle((result, exception) -> {
            if (exception == null) {
                return result;
            }
            System.out.println("handle处理异常：" + exception);
            return 1;
        });
        System.out.println("handle处理返回结果：" + future6.get());

//        // 5.6.1.二者都要完成，组合【不获取前两个任务返回值，且自己无返回值】
//        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务1执行");
//            return 10 / 2;
//        }, executor);
//        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务2执行");
//            return "hello";
//        }, executor);
//        CompletableFuture<Void> future03 = future01.runAfterBothAsync(future02, () -> {
//            System.out.println("任务3执行");
//        }, executor);

//        // 5.6.2.二者都要完成，组合【获取前两个任务返回值，自己无返回值】
//        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务1执行");
//            return 10 / 2;
//        }, executor);
//        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务2执行");
//            return "hello";
//        }, executor);
//        CompletableFuture<Void> future03 = future01.thenAcceptBothAsync(future02,
//                (result1, result2) -> {
//                    System.out.println("任务3执行");
//                    System.out.println("任务1返回值：" + result1);
//                    System.out.println("任务2返回值：" + result2);
//                }, executor);

        // 5.6.3.二者都要完成，组合【获取前两个任务返回值，自己有返回值】
        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1执行");
            return 10 / 2;
        }, executor);
        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2执行");
            return "hello";
        }, executor);
        CompletableFuture<String> future03 = future01.thenCombineAsync(future02,
                (result1, result2) -> {
                    System.out.println("任务3执行");
                    System.out.println("任务1返回值：" + result1);
                    System.out.println("任务2返回值：" + result2);
                    return "任务3返回值";
                }, executor);
        System.out.println(future03.get());


        CompletableFuture<Void> allOf = CompletableFuture.allOf(future01, future02, future03);
        allOf.get();// 阻塞等待所有任务完成

        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future01, future02, future03);
        anyOf.get();// 阻塞等待任一任务完成，返回值是执行成功的任务返回值
    }
}
